<!--
 * @Description: 
 * @Author: your name
 * @version: 
 * @Date: 2024-06-24 09:53:54
 * @LastEditors: your name
 * @LastEditTime: 2024-07-01 10:50:01
-->
<template>
    <a-card title="楼房分户" style="width: 600px;pointer-events: all;">
        <template #extra>
            <UndoOutlined @click="refresh" />
        </template>
        <a-steps :current="currentStep" :items="steps">
        </a-steps>
        <div class="draw-area">
            <span>绘制户型:</span>
            <ForkOutlined class="icon-draw" @click="activeDraw" />
            <span>{{ textDraw }}</span>
        </div>
        <div class="form-area">
            <a-table size="small" bordered :data-source="buildingData" :columns="buildingColumns" :pagination="false">
                <template #bodyCell="{ column, text, record }">
                    <template v-if="['posPrefix', 'unit'].includes(column.dataIndex)">
                        <div>
                            <a-input v-if="editableData[record.key]"
                                v-model:value="editableData[record.key][column.dataIndex]" style="margin: -5px 0" />
                            <template v-else>
                                {{ text }}
                            </template>
                        </div>
                    </template>

                    <!-- 只有做区域绘制的时候，需要编辑 -->
                    <template v-else-if="column.dataIndex === 'operation' && currentStep !== 2">
                        <div class="editable-row-operations">
                            <span v-if="editableData[record.key]" style="display: flex;justify-content: space-around;">
                                <a-typography-link @click="save(record.key)">保存</a-typography-link>
                                <a-popconfirm title="Sure to cancel?" @confirm="cancel(record.key)">
                                    <a>取消</a>
                                </a-popconfirm>
                            </span>
                            <span v-else>
                                <a @click="edit(record.key)">编辑</a>
                            </span>
                        </div>
                    </template>

                    <!-- 只有户型切分的时候，需要定位 -->
                    <template v-if="['positionFix'].includes(column.dataIndex)">
                        <div @click="focusOnArea(record.key)">
                            <img style="cursor: pointer;" width="20" height="20" src="/src/assets/position.png" alt="">
                        </div>
                    </template>
                </template>

            </a-table>
        </div>
        <!-- 楼房分层 -->
        <div class="floor-area" v-if="currentStep === 2 && showDivide">
            <span>最低点:</span>
            <a-input width="100" :value="minHeight" :min="-100" :max="200" :disabled="true"></a-input>
            <span>分割点:</span>
            <a-input width="100" :value="divideHeight" :min="-100" :max="200" :disabled="true"></a-input>
            <span>最高点:</span>
            <a-input width="100" :value="maxHeight" :min="-100" :max="200" :disabled="true"></a-input>
            <span>楼层数:</span>
            <a-input width="100" v-model:value="floorNum" :min="0" :max="100"></a-input>
        </div>
        <div class="button-area">
            <a-button v-if="currentStep < steps.length - 1" type="primary" @click="nextStep">下一步</a-button>
            <a-button v-if="showDivide" @click="divideFloor" style="margin:0 10px;">楼房分层</a-button>
            <a-button v-if="currentStep == steps.length - 1 && updateActive" type="primary" @click="updateInfo">
                生成数据
            </a-button>
        </div>
    </a-card>
</template>

<script setup>
import * as Cesium from 'cesium'
import { ref, reactive, computed, watch,onBeforeUnmount } from 'vue';
import { cloneDeep } from 'lodash'
import {binkEntityMaterial} from '@/cesiumTools/sceneManager.js'
import { changeCartesin3ToGeoJson, polygonCut, cartesian3ToDegreesHeight } from '@/cesiumTools/utils'
import DrawTool from '../cesiumTools/drawTool'
import { UndoOutlined, ForkOutlined } from '@ant-design/icons-vue'
import { useMapData } from '@/store'
import {addHouse} from '@/api/api'
import { message } from 'ant-design-vue';

const mapStore = useMapData()
const viewer = mapStore.Viewer
const drawTool = new DrawTool(viewer)
const currentStep = ref(0)
const showDivide = ref(false)
const updateActive=ref(false)
const minHeight = ref(0)
const divideHeight = ref(0)
const maxHeight = ref(0)
const floorNum = ref(0)

// 推送到服务端的数据
// polygonJson总区域geojson字符串
// polygonJsonArr切割后geojson字符串数组，如果没有切割，传[]
// unitArr 单位数组
// heightArr 三个高度数组
// name 楼栋名称
// floorNum楼层数
const postDataSource={
    polygonJson:'',
    polygonJsonArr:[],
    unitArr:[],
    heightArr:[],
    name:'',
    floorNum:0
}
// 户型设置
const buildingData = ref([])
const buildingColumns = ref([{
    title: '分户坐标',
    dataIndex: 'position',
    align: 'center',
    width: '30%',
    ellipsis: true
}, {
    title: '地址前缀',
    dataIndex: 'posPrefix',
    align: 'center',
    width: '30%',
    ellipsis: true
}, {
    title: '单位',
    dataIndex: 'unit',
    align: 'center'
}, {
    title: '操作',
    dataIndex: 'operation',
    align: 'center'
}])
const editableData = reactive({});
// 可编辑表格配置
const edit = key => {
    editableData[key] = cloneDeep(buildingData.value.filter(item => key === item.key)[0]);
};
const save = key => {
    Object.assign(buildingData.value.filter(item => key === item.key)[0], editableData[key]);
    delete editableData[key];
};
const cancel = key => {
    delete editableData[key];
};

onBeforeUnmount(()=>{
    drawEntLisener && drawTool.removeListener(drawEntLisener)
    refresh()
})

watch(currentStep, (val) => {
    if (val === 0) {
        if (!buildingColumns.value.find(item => item.dataIndex === 'operation')) {
            buildingColumns.value.push({
                title: '操作',
                dataIndex: 'operation',
                align: 'center'
            })
        }
    }
    if (val === 1) {
        if (!buildingColumns.value.find(item => item.dataIndex === 'positionFix')) {
            buildingColumns.value.push({
                title: '定位',
                dataIndex: 'positionFix',
                align: 'center',
                width: '10%'
            })
        }
    }
    // 楼房分层，将后面两列删除
    if (val === 2) {
        buildingColumns.value = buildingColumns.value.filter(item => item.dataIndex !== 'positionFix' && item.dataIndex !== 'operation')
    }
})

const steps = ref([
    {
        title: '区域绘制',
        key: '区域绘制'
    }, {
        title: '户型切分',
        key: '户型切分'
    }, {
        title: '楼房分层',
        key: '楼房分层'
    }
])

const refresh = () => {
    currentStep.value=0
    buildingData.value=[]
    viewer.entities.removeAll()
    primitivesEffect.length && primitivesEffect.forEach(item=>{
        viewer.scene.primitives.remove(item)
    })
    primitivesEffect.length=0
    floorNum.value=0
    updateActive.value=false
    showDivide.value=false
}

const nextStep = () => {
    // 只有区域绘制数据有值的时候，才能往下走
    if (buildingData.value?.length) {
        currentStep.value++
    } else {
        message.warn('请先绘制区域')
    }
}

const textDraw = computed(() => {
    let res = ''
    switch (currentStep.value) {
        case 0:
            res = '绘制图形'
            break;
        case 1:
            res = '户型裁剪'
            break;
        case 2:
            res = '楼层分层'
            break;
        default:
            break;
    }
    return res
})

// 上传服务
const updateInfo =async () => {
    message.loading('正在上传数据...')
    const unitArr=buildingData.value.map(item=>{
        return Number(item.unit)
    })
    const heightArr=[minHeight.value,divideHeight.value,maxHeight.value]
    const name=buildingData.value[0]?.posPrefix
    postDataSource.unitArr=unitArr
    postDataSource.heightArr=heightArr
    postDataSource.name=name
    postDataSource.floorNum=Number(floorNum.value)
    const res=await addHouse(postDataSource)
    if(res.code===200){
        refresh()
        message.success('分户成功')
    }
}

// 定位至区域
const focusOnArea = (key) => {
    const targetEntity=viewer.entities.values.find(item=>item.name===key)
    if(targetEntity){
        binkEntityMaterial(targetEntity)
    }
}

// 设置楼层
const primitivesEffect=[]
const divideFloor = () => {
    if (floorNum.value.length) {
        let itemHeight = (maxHeight.value - divideHeight.value) / (floorNum.value - 1)
        viewer.entities.removeAll()
        buildingData.value.forEach(item => {
            const { position } = item
            console.log(position);
            const positionArr=position.split(',').map(item=>Number(item))
            for (let i = 0; i < floorNum.value; i++) {
                let height, extrudedHeight
                if (i == 0) {
                    height = minHeight.value
                    extrudedHeight = divideHeight.value
                } else {
                    height = divideHeight.value + (i - 1) * itemHeight
                    extrudedHeight = divideHeight.value + i * itemHeight
                }
                let primitive = new Cesium.ClassificationPrimitive({
                    geometryInstances: new Cesium.GeometryInstance({
                        geometry: new Cesium.PolygonGeometry({
                            polygonHierarchy: new Cesium.PolygonHierarchy(new Cesium.Cartesian3.fromDegreesArray(positionArr)),
                            height,
                            extrudedHeight,
                        }),
                        attributes: {
                            color: Cesium.ColorGeometryInstanceAttribute.fromColor(
                                Cesium.Color.fromRandom({ alpha: 0.3 }) //颜色
                            ),
                        },
                    }),
                    classificationType: Cesium.ClassificationType.CESIUM_3D_TILE,
                });
                primitivesEffect.push(primitive)
                viewer.scene.primitives.add(primitive);
                updateActive.value=true
            }
        })
    }
}

let lastDrawEnt
let drawEntLisener
let polygonGeo

// 绘制矩形
const activeDraw = () => {
   
    drawEntLisener && drawTool.removeListener(drawEntLisener)
    if (currentStep.value === 0) {
        // 重新绘制清楚之前绘制的图形
        message.info('点击地图绘制大楼区域')
        drawTool.removeAllDrawEnts()
        drawTool.active(drawTool.DrawTypes.Polygon)
        drawEntLisener = (drawEnt, postions, drawType) => {
            const { geojson, positionLng } = changeCartesin3ToGeoJson(postions, 'polygon')
            if (geojson) {
                polygonGeo = geojson
                // 在table中填入数据
                buildingData.value[0] = {
                    position: positionLng.join(','),
                    posPrefix: 'xxx小区xxx楼栋',
                    unit: '1'
                }
                lastDrawEnt = drawEnt
                // 传入总区域数据
                postDataSource.polygonJson=JSON.stringify(geojson.geometry)
                drawEntLisener && drawTool.removeListener(drawEntLisener)
            }
        }

        drawTool.DrawEndEvent.addEventListener(drawEntLisener)
    } else if (currentStep.value === 1) {
        // 进行户型裁剪
        message.info('点击地图绘制裁剪区域')
        drawTool.active(drawTool.DrawTypes.Polyline)
        drawEntLisener = (drawEnt, postions) => {
            if (postions?.length) {
                drawTool.removeAllDrawEnts()
                const { geojson: lineJson } = changeCartesin3ToGeoJson(postions, 'polyline')
                let polygonCollection
                try {
                    polygonGeo.geometry.coordinates[0] = polygonGeo.geometry.coordinates[0].map(item => item.map(n => Number(n)))
                    lineJson.geometry.coordinates = lineJson.geometry.coordinates.map(item => item.map(n => Number(n)))
                    polygonCollection = polygonCut(polygonGeo, lineJson)
                    // 获取到裁剪之后的geojson数据
                    if (polygonCollection.features.length == 1) {
                        message.error('请切割区域！')
                        return
                    }
                } catch (error) {
                    message.error(error)
                    return
                }
                if (polygonCollection) {
                    // 将裁剪数据传入
                    postDataSource.polygonJsonArr=polygonCollection.features.map(item=>{
                        return JSON.stringify(item.geometry);
                    })

                    // 使用dataSource加载多边形数据
                    Cesium.GeoJsonDataSource.load(polygonCollection, { clampToGround: true }).then(info => {
                        lastDrawEnt && viewer.entities.remove(lastDrawEnt)
                        const dataSource = []
                        lastDrawEnt = null
                        info.entities.values.forEach((item, index) => {
                            item.polygon.material = Cesium.Color.fromRandom({ alpha: 0.5 })
                            viewer.entities.add(item)
                            item.name=index

                            dataSource.push({
                                key: index,
                                position: polygonCollection.features[index].geometry.coordinates.toString(),
                                posPrefix: buildingData.value[0].posPrefix,
                                unit: index + 1
                            })
                        })
                        buildingData.value = dataSource
                        drawEntLisener && drawTool.removeListener(drawEntLisener)
                    })
                }
            }
        }
        drawTool.DrawEndEvent.addEventListener(drawEntLisener)
    } else {
        // 楼房分层
        message.info('点击地图绘制大楼底层，二楼以及顶楼高度点')
        drawTool.active(drawTool.DrawTypes.Point)
        drawEntLisener = (drawEnt, positions) => {
            if (positions.length === 3) {
                let positionsPerHeight = positions.map(item => {
                    const positionLng = cartesian3ToDegreesHeight(item)
                    return positionLng[2]
                })
                positionsPerHeight.sort((a, b) => a - b)
                minHeight.value = positionsPerHeight[0]
                divideHeight.value = positionsPerHeight[1]
                maxHeight.value = positionsPerHeight[2]
                showDivide.value = true
            } else {
                message.warn('请绘制底层，二楼以及顶楼高度点')
                drawTool.removeAllDrawEnts()
                return
            }
            drawEntLisener && drawTool.removeListener(drawEntLisener)
        }
        drawTool.DrawEndEvent.addEventListener(drawEntLisener)
    }
}


</script>
<style scoped>
.button-area {
    display: flex;
    justify-content: flex-end;
    margin-top: 20px;
}

.draw-area {
    margin: 20px 0;
}

.draw-area span {
    margin: 0 4px;
}

.icon-draw {
    padding: 4px;
}

.icon-draw:hover {
    cursor: pointer;
    background-color: skyblue;
    color: #fff;
}

.floor-area span{
    margin: 0 10px;
}
</style>